import java.util.ArrayList;


public class Utility {

	public Utility(){
		
	}
	
	public static String[] StringSplitByDelimiter(String toSplit, String delimiter){
		
		String[] splitted= toSplit.split(delimiter);
		
		return splitted;
	}
	
	public static ArrayList<String> ArrayToList(String[] toCopy){
		
		ArrayList<String> list= new ArrayList<String>();
		
		for(String a: toCopy){
			if(!a.equals("")) list.add(a);
		}
		
		return list;
	}
	
	public static boolean isNullable(Productions P, String A, ArrayList<String> nullable, ArrayList<String> viewed){
		
		String epsilon= "e";
		
		if(!viewed.contains(A)){

			viewed.add(A);
			if(P.isPresent(A)){
				
				ArrayList<String> lhs= P.getProductionByKey(A).getLHS();
						
				for(String tmp : lhs){
					
					if(!viewed.contains(tmp)){
					
						if(tmp.equals(epsilon)) {
							
							viewed.add(tmp);
							nullable.add(tmp);
							return true;
						}
						else if(tmp.length() == 1){
							
							if(!nullable.contains(tmp)){
								
								if(isNullable(P, tmp, nullable, viewed)) {

									viewed.add(tmp);
									nullable.add(tmp);
									return true;
								}
							}
						}
						else{
		
							boolean isNullable= true;
							for(char c : tmp.toCharArray()){
							
								if(!nullable.contains(Character.toString(c))) isNullable= false; 
							}
							if(isNullable == true)  {

								viewed.add(tmp);
								nullable.add(tmp);
								return true;
							}
						}
					}
				}
			}
			else{

				if(A.length() == 1){
					
					if(!nullable.contains(A)){
						
						if(isNullable(P, A, nullable, viewed))  {

							viewed.add(A);
							nullable.add(A);
							return true;
						}
					}
				}
				else{

					boolean isNullable= true;
					for(char c : A.toCharArray()){
					
						if(!nullable.contains(Character.toString(c))) isNullable= false; 
					}
					if(isNullable == true)  {

						viewed.add(A);
						nullable.add(A);
						return true;
					}
				}
			}
		
		}
			
		return false;
	}
	
	public static boolean isUnit(String A, String B, ArrayList<String> VN){
		
		if(VN.contains(A) && VN.contains(B)){
			
			if(!A.equals(B) && B.length()==1) return true;
		}
		
		return false;
	}
	
	public static boolean isTrivialUnit(String A, String B, ArrayList<String> VN){
		
		if(VN.contains(A) && VN.contains(B)){
			
			if(A.equals(B) && B.length()==1) return true;
		
		}
		return false;
	}
	
	public static boolean  isAllNonTerminal(String s){
		
		for(char c : s.toCharArray()){
			
			if(!Character.isUpperCase(c) && c!='|'){
				
				return false;
			}
		}
		
		return true;
	}
	
	public static ArrayList<String> combine(String c){
		
		ArrayList<String> single= new ArrayList<String>();
		ArrayList<String> combined= new ArrayList<String>();
		
		//inserisco la stringa intera
		combined.add(c);
		combined.add("|");
		
		//inserisco i termini singoli
		for(char g : c.toCharArray()){
			
			String str= Character.toString(g);
			single.add(str);
			if(!combined.contains(str)) {

				combined.add(str);
				combined.add("|");
			}
		}
		
		//combino i singoli
		int start=0, end=0;
		for(String s : single){
			
			singleCombine(start, end, single, combined);
			start++;
		}
		
		return combined;
	}
	
	public static void singleCombine(int start, int end,ArrayList<String> a, ArrayList<String> combined){
		
		if(end<a.size()){
			
			//creo la parte statica della combinazione di caratteri
			String A= "";
			for(int j=start; j<=end; j++){
				
				A+= a.get(j);
			}
			
			//aggiungo la parte dinamica
			for(int i=end+1; i<a.size(); i++){
				
				String o= A+a.get(i);
				if(!combined.contains(o)){
					
					combined.add(o);
					combined.add("|");
				}
			}
			end++;
			//richiamo ricorsivamente la funzione per cambiare livello di profondità nelle combinazioni
			singleCombine(start, end, a, combined);
		}
	}
}
